﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using NHibernate.Hql.Ast;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
using NHibernate.Linq.Visitors;

namespace NHDay_Linq.ProviderExtensions
{
	public static class CustomGetMonthExtension
	{
		public static int CustomGetMonth(this DateTime date)
		{
			//return date.Month;
            throw new NotSupportedException();
		}

		// simple way: not suitable to any scenario especially when the order of the arguments is important
		//[LinqExtensionMethod("dbo.customgetmonth")]
		//public static int CustomGetMonth2(this DateTime date)
		//{
		//    return date.Month;
		//}
	}

	/// <summary>
	/// The actual generator that contains the methods that build the expression to be used by the linq provider
	/// 
	/// it 'translate' our function call to the actual SQL custom function
	/// </summary>
	public class CustomGetMonthGenerator : BaseHqlGeneratorForMethod
	{
		public CustomGetMonthGenerator()
		{
			SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => CustomGetMonthExtension.CustomGetMonth(DateTime.Now)) };
		}

		public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
			ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
		{
			IEnumerable<HqlExpression> args = arguments.Select(a => visitor.Visit(a))
				.Cast<HqlExpression>();

			return treeBuilder.MethodCall("dbo.customgetmonth", args);
		}
	}
}
